// 接口
import api from './index';
import type { Auth } from './data';
// 工具
import request from './request';
import { Toast } from '@/utils/util';

async function readFile(uniFile: any) {
  // 微信小程序
  if (uni.getFileSystemManager) {
    const fs = uni.getFileSystemManager();
    return fs.readFileSync(uniFile.path);
  }
  // H5 等
  return uniFile.arrayBuffer();
}

/**
 * 七牛云直传单个文件
 * @param {Object} file 文件对象
 * @param {String} directory 存储目录
 * @param {Function} onProgress 进度回调
 * @returns {Promise}
 */
export const uploadToQiniu = async (file: any, directory: string) => {
  try {
    const fileExt = getFileExtension(file.name)

    // 1.1 获取文件预签名地址
    const { data: presignedInfo } = await api.Common.getQiniuUrl({
      name: wxuuid() + (fileExt ? ('.' + fileExt) : ''),
      directory,
    });

    // 1.2 获取二进制文件对象
    const fileBuffer = await readFile(file);

    // 返回上传的 Promise
    return new Promise((resolve, reject) => {
      // 1.3. 上传文件到七牛云
      uni.request({
        url: presignedInfo.uploadUrl,
        method: 'PUT',
        header: {
          'Content-Type': file.type || 'application/octet-stream',
        },
        data: fileBuffer,
        success: async res => {
          try {
            // 1.4. 记录文件信息到后端（异步）
            await api.Common.createNum({
              configId: presignedInfo.configId,
              url: presignedInfo.url,
              path: presignedInfo.path,
              name: file.name,
              type: file?.fileType,
              size: file?.size,
            });
            // 1.5. 重新赋值
            const result = {
              ...file,
              url: presignedInfo.url,
              uploadUrl: presignedInfo.uploadUrl,
            };
            resolve(result);
          } catch (err) {
            console.error('记录文件信息失败:', err);
            // 即使记录失败，文件已上传成功，仍返回成功结果
            resolve({
              ...file,
              url: presignedInfo.url,
              uploadUrl: presignedInfo.uploadUrl,
            });
          }
        },
        fail: err => {
          reject(err);
        },
      });
    });
  } catch (error) {
    throw error;
  }
};

/**
 * 判断文件是否为图片类型
 * @param {String} fileType 文件类型
 * @returns {Boolean}
 */
const isImageFile = (fileType: string): boolean => {
  if (!fileType) return false;
  const imageTypes = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'];
  return imageTypes.includes(fileType.toLowerCase());
};

/**
 * 打开或预览文件
 * @param {String} filePath 文件路径
 * @param {String} fileType 文件类型
 * @returns {Promise}
 */
const openFile = (filePath: string, fileType: string): Promise<any> => {
  console.log('openFile', filePath, fileType);
  return new Promise((resolve, reject) => {
    if (isImageFile(fileType)) {
      // 图片使用预览
      uni.previewImage({
        urls: [filePath],
        current: filePath,
        success: res => {
          console.log('图片预览成功', res);
          resolve(res);
        },
        fail: err => {
          console.error('图片预览失败', err);
          uni.showToast({
            title: '图片预览失败',
            icon: 'none',
          });
          reject(err);
        },
      });
    } else {
      // 文档使用打开
      const openDocumentParams = {
        filePath: filePath,
        showMenu: true,
        success: res => {
          console.log('文件打开成功', res);
          resolve(res);
        },
        fail: err => {
          console.error('文件打开失败', err);
          uni.showToast({
            title: '文件打开失败',
            icon: 'none',
          });
          reject(err);
        },
      };

      // 如果提供了文件类型，并且 openDocument 支持 fileType，则动态添加
      if (fileType && 'fileType' in uni.openDocument) {
        // @ts-ignore
        openDocumentParams.fileType = fileType;
      }

      uni.openDocument(openDocumentParams);
    }
  });
};

/**
 * 根据文件扩展名获取文件类型
 * @param {String} extension 文件扩展名（带点）
 * @returns {String} 文件类型（去掉点号的扩展名）
 */
const getFileTypeFromExtension = (extension: string): string | null => {
  if (!extension) return null;

  return extension.toLowerCase().replace('.', '');
};

/**
 * 从响应对象中下载文件
 * @param {Object} response - 响应对象，包含二进制数据
 * @param {String} fileName - 文件名（可以不包含扩展名，函数会自动检测）
 * @returns {Promise} 下载结果的Promise
 */
export const downloadFileFromResponse = (response: Record<string, any>, fileName?: string): Promise<any> => {
  return new Promise((resolve, reject) => {
    try {
      console.log('下载文件响应:', response);

      const data = response.data; // 获取二进制数据

      // 检查数据类型
      if (!data) {
        throw new Error('响应数据为空');
      }

      console.log('数据类型:', typeof data, 'ArrayBuffer:', data instanceof ArrayBuffer);

      // 从响应头获取文件类型信息
      const contentType = response.header['content-type'] || response.header['Content-Type'] || '';
      const contentDisposition = response.header['content-disposition'] || response.header['Content-Disposition'] || '';

      console.log('响应头信息:', {
        contentType,
        contentDisposition,
      });

      // 处理文件名和扩展名
      let finalFileName = fileName;
      let fileExtension = '';
      let serverFileName = '';

      // 1. 尝试从 Content-Disposition 头中获取文件名
      if (contentDisposition && contentDisposition.includes('filename=')) {
        const match = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
        if (match && match[1]) {
          serverFileName = match[1].replace(/['"]/g, '');
          // 从服务器文件名中提取扩展名
          const extMatch = serverFileName.match(/\.[^.]*$/);
          if (extMatch) {
            fileExtension = extMatch[0];
          }
        }
      }

      // 2. 如果没有从 Content-Disposition 获取到扩展名，根据 Content-Type 判断
      if (!fileExtension) {
        if (contentType.includes('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')) {
          fileExtension = '.xlsx';
        } else if (contentType.includes('application/vnd.ms-excel')) {
          fileExtension = '.xls';
        } else if (contentType.includes('application/pdf')) {
          fileExtension = '.pdf';
        } else if (contentType.includes('application/msword')) {
          fileExtension = '.doc';
        } else if (contentType.includes('application/vnd.openxmlformats-officedocument.wordprocessingml.document')) {
          fileExtension = '.docx';
        } else if (contentType.includes('image/jpeg')) {
          fileExtension = '.jpg';
        } else if (contentType.includes('image/png')) {
          fileExtension = '.png';
        } else if (contentType.includes('image/gif')) {
          fileExtension = '.gif';
        } else if (contentType.includes('image/bmp')) {
          fileExtension = '.bmp';
        } else if (contentType.includes('image/webp')) {
          fileExtension = '.webp';
        } else if (contentType.includes('image/')) {
          fileExtension = '.jpg'; // 默认为 jpg
        } else {
          // 默认为 Excel 格式
          fileExtension = '.xlsx';
        }
      }

      const _fileName = fileName || serverFileName;
      // 3. 检查传入的文件名是否已经有扩展名
      const hasExtension = /\.[^.]*$/.test(_fileName);
      if (!hasExtension && fileExtension) {
        finalFileName = _fileName + fileExtension;
      }

      console.log('最终文件名:', finalFileName);

      // 使用微信小程序的临时文件路径
      const filePath = `${wx.env.USER_DATA_PATH}/${finalFileName}`;

      // 显示加载提示
      uni.showLoading({
        title: '正在下载文件',
        mask: true,
      });

      // 获取文件系统管理器
      const fs = uni.getFileSystemManager();

      // 确保数据是 ArrayBuffer 格式
      let fileData = data;
      if (!(data instanceof ArrayBuffer)) {
        // 如果不是 ArrayBuffer，尝试转换
        if (typeof data === 'string') {
          // 如果是字符串，转换为 ArrayBuffer
          const encoder = new TextEncoder();
          fileData = encoder.encode(data).buffer;
        } else {
          throw new Error('不支持的数据格式');
        }
      }

      // 写入文件
      fs.writeFile({
        filePath: filePath,
        data: fileData,
        success: res => {
          uni.hideLoading();

          // 显示成功提示
          uni.showToast({
            title: '下载成功',
            icon: 'success',
            duration: 2000,
          });

          // 根据文件扩展名获取文档类型
          const fileType = getFileTypeFromExtension(fileExtension);

          // 使用公共方法打开文件
          openFile(filePath, fileType)
            .then(() => resolve(res))
            .catch(() => resolve(res));
        },
        fail: err => {
          uni.hideLoading();
          console.error('文件写入失败', err);

          uni.showToast({
            title: '文件下载失败',
            icon: 'none',
            duration: 2000,
          });

          reject(err);
        },
      });
    } catch (error) {
      uni.hideLoading();
      console.error('下载文件异常', error);

      uni.showToast({
        title: '下载异常',
        icon: 'none',
        duration: 2000,
      });

      reject(error);
    }
  });
};

/**
 * 刷新令牌
 */
export const fetchRefreshToken = async (refreshToken: string) => {
  try {
    const res = await request<Auth.Login.Data>('/member/auth/refresh-token', 'GET', { refreshToken });
    uni.setStorageSync('auth', res.data);
  } catch (error: any) {
    console.error(error);
    Toast(JSON.stringify(error.msg));
  }
};

export const getFileExtension = (filename)=> {
  const lastDotIndex = filename.lastIndexOf('.');
  if (lastDotIndex === -1 || lastDotIndex === filename.length - 1) {
    return '';
  }
  return filename.substring(lastDotIndex + 1);
}

export const wxuuid = function () {
  var s = [];
  var hexDigits = "0123456789abcdef";
  for (var i = 0; i < 36; i++) {
    s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
  }
  s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
  s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
  s[8] = s[13] = s[18] = s[23] = "-";
  var uuid = s.join("").replace("-","");
  return uuid
}
